package com.macro.mall.service.impl;

import cn.hutool.core.util.ObjUtil;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.macro.mall.common.config.XhsApiConfig;
import com.macro.mall.common.exception.BaseException;
import com.macro.mall.common.exception.XhsApiException;
import com.macro.mall.dto.PoiInfoDTO;
import com.macro.mall.mapper.XhsStoreMapper;
import com.macro.mall.model.StoreQueryParam;
import com.macro.mall.model.XhsStore;
import com.macro.mall.model.request.AuthTokenRequest;
import com.macro.mall.model.request.PlaceQueryRequest;
import com.macro.mall.model.response.*;
import com.macro.mall.model.vo.store.XhsStoreVo;
import com.macro.mall.service.PoiFacilityService;
import com.macro.mall.service.XhsLoginService;
import com.macro.mall.utils.GaodeCityInfoFetcher;
import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.core.type.TypeReference;
import okhttp3.HttpUrl;
import okhttp3.Request;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.net.URIBuilder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PoiFacilityServiceImpl implements PoiFacilityService {



    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private XhsApiConfig apiConfig;

    @Resource
    private XhsLoginService xhsLoginService;


    @Resource
    private XhsStoreMapper xhsStoreMapper;

    @Override
    public FacilityListResponse getAllFacilityTags() throws RuntimeException {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 1. 获取API地址
            String apiUrl = apiConfig.getBaseUrl() + "/api/rmp/tp/poi/facility/listall";

            // 2. 获取有效auth_access_token
            String authAccessToken = null;
            try {
                authAccessToken = xhsLoginService.getValidToken();
            } catch (XhsApiException e) {
                throw new RuntimeException(e);
            }
            if (!StringUtils.hasText(authAccessToken)) {
                log.info("获取auth_access_token失败");
            }

            // 3. 构建请求URL
            URIBuilder uriBuilder = new URIBuilder(apiUrl)
                    .addParameter("app_id", apiConfig.getAppId())
                    .addParameter("auth_access_token", authAccessToken);

            // 4. 构建HTTP请求
            HttpGet httpGet = new HttpGet(uriBuilder.build());
            httpGet.setHeader("Content-Type", "application/json");

            // 5. 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                if (response.getCode() != 200) {
                    String errorMsg = String.format("获取门店设施标签失败，状态码: %d", response.getCode());
                    log.error(errorMsg);
                }

                // 6. 解析响应
                String responseBody = EntityUtils.toString(response.getEntity());
                FacilityListResponse facilityResponse = objectMapper.readValue(responseBody, FacilityListResponse.class);

                if (facilityResponse == null || facilityResponse.getList() == null) {
                    log.info("门店设施标签响应数据解析失败");
                }

                // 7. 记录获取结果
                log.info("成功获取门店设施标签，共{}种类型", facilityResponse.getList().size());

                return facilityResponse;
            }
        } catch (Exception e) {
            log.error("获取门店设施标签网络异常", e);
        }
        return null;
    }






















    @Override
    public XhsBaseResponse<PoiListData> getPoiList(Integer pageNo, Integer pageSize) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 1. 获取API地址
            String apiUrl = apiConfig.getBaseUrl() + "/api/rmp/mp/deal/poi/list";

            // 2. 获取有效access_token
            String accessToken = xhsLoginService.getValidToken();
            if (!StringUtils.hasText(accessToken)) {
                log.error("获取access_token失败");
                return null;
            }

            // 3. 构建请求URL（包含查询参数）
            URIBuilder uriBuilder = new URIBuilder(apiUrl)
                    .addParameter("app_id", apiConfig.getAppId())
                    .addParameter("access_token", accessToken);

            // 4. 构建请求体参数
            Map<String, Object> requestParams = new HashMap<>();
            if (pageNo != null) {
                requestParams.put("page_no", pageNo);
            }
            if (pageSize != null) {
                requestParams.put("page_size", Math.min(pageSize, 100));
            }

            // 5. 构建请求体
            String jsonBody = objectMapper.writeValueAsString(requestParams);

            // 6. 创建GET请求并设置请求体
            HttpGet httpGet = new HttpGet(uriBuilder.build());
            StringEntity entity = new StringEntity(jsonBody);
            httpGet.setEntity(entity);
            httpGet.setHeader("Content-Type", "application/json");

            // 7. 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                if (response.getCode() != 200) {
                    log.error("获取POI列表失败，状态码: {}", response.getCode());
                    return null;
                }

                // 8. 解析响应
                String responseBody = EntityUtils.toString(response.getEntity());
                XhsBaseResponse<PoiListData> responseObj = objectMapper.readValue(
                        responseBody,
                        new TypeReference<XhsBaseResponse<PoiListData>>() {}
                );

                if (responseObj == null || !responseObj.getSuccess() ||
                        responseObj.getData() == null || responseObj.getData().getList() == null) {
                    log.error("POI列表响应数据解析失败");
                    return null;
                }

                // 9. 记录获取结果
                log.info("成功获取POI列表，共{}条记录，总数: {}",
                        responseObj.getData().getList().size(),
                        responseObj.getData().getTotal());

                return responseObj;
            }
        } catch (Exception e) {
            log.error("获取POI列表网络异常", e);
            throw new Exception("获取POI列表网络异常", e);
        }
    }
    @Override
    public List<PoiInfoDTO> findAllPoi() {


        List<PoiInfoDTO> allPoiList = new ArrayList<>();
        int page = 1;
        int pageSize = 100; // 每次查询100条
        boolean hasMore = true;

        while (hasMore) {
            try {
                XhsBaseResponse<PoiListData> response = this.getPoiList(page, pageSize);
                if (response != null && response.getData() != null) {
                    List<PoiInfoDTO> currentPageList = response.getData().getList();
                    if (currentPageList != null && !currentPageList.isEmpty()) {
                        allPoiList.addAll(currentPageList);
                        // 检查是否还有更多数据
                        if (currentPageList.size() < pageSize) {
                            hasMore = false;
                        }
                    } else {
                        hasMore = false;
                    }
                } else {
                    hasMore = false;
                }
                page++; // 翻到下一页
            } catch (Exception e) {
                log.error("获取POI列表失败，页码: {}", page, e);
                throw new RuntimeException("获取POI列表失败", e);
            }
        }
        return allPoiList;
    }


    @Override
    public PlaceQueryResponse queryPlaces(PlaceQueryRequest request) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 1. 获取API地址
            String apiUrl = apiConfig.getBaseUrl() + "/api/rmp/place/query";

            // 2. 获取有效access_token
            String accessToken = xhsLoginService.getValidToken();
            if (!StringUtils.hasText(accessToken)) {
                log.error("获取access_token失败");

            }

            // 3. 构建请求URL
            URIBuilder uriBuilder = new URIBuilder(apiUrl)
                    .addParameter("app_id", apiConfig.getAppId())
                    .addParameter("access_token", accessToken);

            // 4. 构建请求体
            String jsonBody = objectMapper.writeValueAsString(request);
            StringEntity entity = new StringEntity(jsonBody);

            // 5. 构建HTTP请求
            HttpPost httpPost = new HttpPost(uriBuilder.build());
            httpPost.setEntity(entity);
            httpPost.setHeader("Content-Type", "application/json");

            // 6. 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                if (response.getCode() != 200) {
                    String errorMsg = String.format("查询可用地点失败，状态码: %d", response.getCode());
                    log.error(errorMsg);

                }

                // 7. 解析响应
                String responseBody = EntityUtils.toString(response.getEntity());
                PlaceQueryResponse queryResponse = objectMapper.readValue(responseBody, PlaceQueryResponse.class);

                if (queryResponse == null || !queryResponse.getSuccess() ||
                        queryResponse.getData() == null || queryResponse.getData().getPlaceList() == null) {
                    log.error("查询地点响应数据解析失败");
                    throw new BaseException("地点数据为空");

                }

                // 8. 记录查询结果
                log.info("成功查询到{}个可用地点", queryResponse.getData().getPlaceList().size());

                return queryResponse;
            }
        } catch (Exception e) {
            log.error("查询可用地点网络异常", e);
            throw new Exception("查询可用地点网络异常", e);
        }
    }
















    @Override
    public PoiProductListResponse getProductsByPoi(String poiId) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 1. 获取API地址
            String apiUrl = apiConfig.getBaseUrl() + "/api/rmp/tp/poi/spu/list";

            // 2. 获取有效auth_access_token
            PreAuthCodeResponse preAuthCode = xhsLoginService.getPreAuthCode();
            AuthTokenRequest authTokenRequest = new AuthTokenRequest();
            authTokenRequest.setAuthCode(preAuthCode.getData().getPreAuthCode());
            AuthTokenResponse authToken = xhsLoginService.getAuthToken(authTokenRequest);
            String authAccessToken = authToken.getData().getAuthAccessToken();
            if (!StringUtils.hasText(authAccessToken)) {
                log.error("获取auth_access_token失败");
                return null;
            }

            // 3. 构建请求URL
            URIBuilder uriBuilder = new URIBuilder(apiUrl)
                    .addParameter("app_id", apiConfig.getAppId())
                    .addParameter("auth_access_token", authAccessToken)
                    .addParameter("poi_id", poiId);

            // 4. 构建HTTP请求
            HttpGet httpGet = new HttpGet(uriBuilder.build());
            httpGet.setHeader("Content-Type", "application/json");

            // 5. 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                if (response.getCode() != 200) {
                    String errorMsg = String.format("获取POI商品列表失败，状态码: %d", response.getCode());
                    log.error(errorMsg);
                    return null;
                }

                // 6. 解析响应
                String responseBody = EntityUtils.toString(response.getEntity());
                PoiProductListResponse productResponse = objectMapper.readValue(responseBody, PoiProductListResponse.class);

                if (productResponse == null || !productResponse.getSuccess() ||
                        productResponse.getData() == null || productResponse.getData().getList() == null) {
                    log.error("POI商品列表响应数据解析失败");
                    return null;
                }

                // 7. 记录查询结果
                log.info("成功获取POI[{}]下的商品列表，共{}个商品",
                        poiId, productResponse.getData().getList().size());

                return productResponse;
            }
        } catch (Exception e) {
            log.error("获取POI商品列表网络异常", e);
            throw new Exception("获取POI商品列表网络异常", e);
        }
    }

    @Override
    public void saveStoreDB() {
        List<PoiInfoDTO> allPoi = this.findAllPoi();
        List<XhsStore> newStores = new ArrayList<>();

        for (PoiInfoDTO poi : allPoi) {
            // 通过poiId查询是否已存在
            XhsStore existingStore = xhsStoreMapper.selectByPoiId(poi.getPoi_id());

            if (existingStore != null) {
                // 已存在，更新数据
                existingStore.setAddress(poi.getAddress());
                existingStore.setLatitude(poi.getLatitude());
                existingStore.setLongitude(poi.getLongitude());
                String city = GaodeCityInfoFetcher.getCityByCoordinates(String.valueOf(poi.getLongitude()), String.valueOf(poi.getLatitude()));
                existingStore.setCity(city);
                existingStore.setName(poi.getName());

                // 更新已存在的记录
                xhsStoreMapper.update(existingStore);
                log.info("更新小红书门店信息：poiId={}, name={}", poi.getPoi_id(), poi.getName());
            } else {
                // 不存在，创建新记录
                XhsStore xhsStore = new XhsStore();
                xhsStore.setPoiId(poi.getPoi_id());
                xhsStore.setAddress(poi.getAddress());
                xhsStore.setLatitude(poi.getLatitude());
                xhsStore.setLongitude(poi.getLongitude());
                String city = GaodeCityInfoFetcher.getCityByCoordinates(String.valueOf(poi.getLongitude()), String.valueOf(poi.getLatitude()));
                xhsStore.setCity(city);
                xhsStore.setName(poi.getName());

                newStores.add(xhsStore);
            }
        }

        // 批量插入新记录
        if (!newStores.isEmpty()) {
            xhsStoreMapper.batchInsert(newStores);
            log.info("批量新增小红书门店信息：{}条", newStores.size());
        }
    }

    @Override
    public List<XhsStoreVo> selStore(StoreQueryParam storeQueryParam ) {


        // 参数校验
        if (storeQueryParam == null) {
            throw new IllegalArgumentException("查询参数不能为空");
        }

        // 计算偏移量
        int offset = (storeQueryParam.getPageNum() - 1) * storeQueryParam.getPageSize();
        // 查询数据
        List<com.macro.mall.model.XhsStoreVo> xhsStoreVos = xhsStoreMapper.selectStoresWithDistance(
                storeQueryParam.getCity(),
                storeQueryParam.getLongitude(),
                storeQueryParam.getLatitude(),
                storeQueryParam.getName(),
                offset,
                storeQueryParam.getPageSize()
        );

        return convertToTargetVoList(xhsStoreVos);
    }

    @Override
    public List<String> getCityList() {
        List<String> cityList = xhsStoreMapper.getCityList();
        return cityList.stream()
                .filter(city -> city != null && !city.isEmpty())
                .collect(Collectors.toList());
    }

    @Override
    public String selCity(StoreQueryParam storeQueryParam) {
        String city = GaodeCityInfoFetcher.getCityByCoordinates(String.valueOf(storeQueryParam.getLongitude()), String.valueOf(storeQueryParam.getLatitude()));
        return city;
    }

    private List<com.macro.mall.model.vo.store.XhsStoreVo> convertToTargetVoList(
            List<com.macro.mall.model.XhsStoreVo> sourceList) {
        if (sourceList == null) {
            return Collections.emptyList();
        }

        return sourceList.stream()
                .map(this::convertToTargetVo)
                .collect(Collectors.toList());
    }

    private com.macro.mall.model.vo.store.XhsStoreVo convertToTargetVo(
            com.macro.mall.model.XhsStoreVo source) {
        if (source == null) {
            return null;
        }

        com.macro.mall.model.vo.store.XhsStoreVo target = new com.macro.mall.model.vo.store.XhsStoreVo();
        target.setId(source.getId());
        target.setPoiId(source.getPoiId());
        target.setName(source.getName());
        target.setAddress(source.getAddress());
        target.setCity(source.getCity());
        if (ObjUtil.isNotEmpty(source.getPhone())){
            target.setPhone(source.getPhone());
        }
        target.setLongitude(source.getLongitude());
        target.setLatitude(source.getLatitude());
        target.setSourceId(source.getSourceId());
        target.setSourceType(source.getSourceType());
        target.setSourceName(source.getSourceName());
        target.setDistance(source.getDistance());

        return target;
    }
    private PoiProductListResponse buildErrorResponse(String errorMsg) {
        PoiProductListResponse response = new PoiProductListResponse();
        response.setSuccess(false);
        response.setMsg(errorMsg);
        response.setCode(500);
        return response;
    }

    @Override
    public Map<String, Integer> importStorePhoneFromExcel(MultipartFile file) throws Exception {
        Map<String, Integer> result = new HashMap<>();
        int successCount = 0;
        int failCount = 0;

        try (InputStream inputStream = file.getInputStream()) {
            // 创建工作簿
            Workbook workbook = new XSSFWorkbook(inputStream);
            // 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);

            // 跳过表头行
            int startRow = 1;
            int lastRowNum = sheet.getLastRowNum();

            log.info("开始导入Excel更新门店手机号，共{}行数据", lastRowNum);

            for (int i = startRow; i <= lastRowNum; i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue;
                }

                try {
                    // 读取Excel中的数据
                    String poiId = getCellValueAsString(row.getCell(0));
                    String storeName = getCellValueAsString(row.getCell(1));
                    String phone = getCellValueAsString(row.getCell(2));

                    // 数据验证
                    if (!StringUtils.hasText(poiId) || !StringUtils.hasText(phone)) {
                        log.warn("第{}行数据不完整，门店ID: {}, 手机号: {}", i + 1, poiId, phone);
                        failCount++;
                        continue;
                    }

                    // 查询门店是否存在
                    XhsStore store = xhsStoreMapper.selectByPoiId(poiId);
                    if (store == null) {
                        log.warn("第{}行门店不存在，门店ID: {}, 门店名称: {}", i + 1, poiId, storeName);
                        failCount++;
                        continue;
                    }

                    // 更新手机号
                    store.setPhone(phone);
                    int updateResult = xhsStoreMapper.update(store);

                    if (updateResult > 0) {
                        successCount++;
                        log.info("成功更新门店手机号，门店ID: {}, 门店名称: {}, 手机号: {}", poiId, storeName, phone);
                    } else {
                        failCount++;
                        log.warn("更新门店手机号失败，门店ID: {}, 门店名称: {}", poiId, storeName);
                    }
                } catch (Exception e) {
                    failCount++;
                    log.error("处理第{}行数据时发生异常", i + 1, e);
                }
            }

            workbook.close();
        } catch (IOException e) {
            log.error("解析Excel文件时发生异常", e);
            throw new Exception("解析Excel文件失败", e);
        }

        result.put("success", successCount);
        result.put("fail", failCount);
        return result;
    }

    /**
     * 获取单元格的字符串值
     * @param cell Excel单元格
     * @return 单元格的字符串值
     */
    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    // 处理数字格式，避免科学计数法
                    double value = cell.getNumericCellValue();
                    long longValue = (long) value;
                    if (value == longValue) {
                        return String.valueOf(longValue);
                    } else {
                        return String.valueOf(value);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return String.valueOf(cell.getStringCellValue());
                } catch (Exception e) {
                    try {
                        return String.valueOf(cell.getNumericCellValue());
                    } catch (Exception ex) {
                        return "";
                    }
                }
            default:
                return "";
        }
    }
}
